package $2_2coreclasses;

public class FnEnum {

    public static void main(String[] args) {
        // 枚举类
        // 为了让编译器能自动检查某个值在枚举的集合内，并且，不同用途的枚举需要不同的类型来标记，不能混用，我们可以使用enum来定义枚举类。
        Weekday day = Weekday.SUN;
        if (day == Weekday.SAT || day == Weekday.SUN) {
            System.out.println("Work at home!");
        } else {
            System.out.println("Work at office!");
        }
        
        Weekdayszh day1 = Weekdayszh.SUN;
        if (day1.dayValue == 6 || day1.dayValue == 0) {
            System.out.println("Today is " + day1.name() + day1.toString() + ". Work at home!");
        } else {
            System.out.println("Today is " + day1.name() + day1.toString() + ". Work at office!");
        }
        
        //switch，加上default语句，可以在漏写某个枚举常量时自动报错，从而及时发现错误。
        switch(day) {
        case MON:
        case TUE:
        case WED:
        case THU:
        case FRI:
            System.out.println("Today is " + day + ". Work at office!");
            break;
        case SAT:
        case SUN:
            System.out.println("Today is " + day + ". Work at home!");
            break;
        default:
            throw new RuntimeException("cannot process " + day);
        }
        
        // enum的比较
        // 使用enum定义的枚举类是一种引用类型。引用类型比较，要使用equals()方法，但enum类型可以例外。因为enum类型的每个常量在JVM中只有一个唯一实例，所以可以直接用==比较。
        if (day == Weekday.FRI) { // ok!
        }
        if (day.equals(Weekday.SUN)) { // ok, but more code!
        }
        
        // enum类型
        // enum定义的类型就是class，只不过它有以下几个特点：
        // 定义的enum类型总是继承自java.lang.Enum，且无法被继承；
        // 只能定义出enum的实例，而无法通过new操作符创建enum的实例；
        // 定义的每个实例都是引用类型的唯一实例；
        // 可以将enum类型用于switch语句。
        
        // name()
        String s = Weekday.SUN.name(); // "SUN"

        // ordinal() 返回定义的常量的顺序，从0开始计数，例如：
        int n = Weekday.MON.ordinal(); // 1

        
    }
    // 注意到定义枚举类是通过关键字enum实现的，我们只需依次列出枚举的常量名。
    // 使用enum定义枚举有如下好处：
    // 首先，enum常量本身带有类型信息，即Weekday.SUN类型是Weekday，编译器会自动检查出类型错误。
    // 其次，不可能引用到非枚举的值，因为无法通过编译。
    // 最后，不同类型的枚举不能互相比较或者赋值，因为类型不符。例如，不能给一个Weekday枚举类型的变量赋值为Color枚举类型的值：
    enum Weekday {
        SUN, MON, TUE, WED, THU, FRI, SAT;
    }
    // 因为enum本身是class，所以我们可以定义private的构造方法，并且，给每个枚举常量添加字段。
    // 这样就无需担心顺序的变化，新增枚举常量时，也需要指定一个int值。
    enum Weekdays {
        MON(1), TUE(2), WED(3), THU(4), FRI(5), SAT(6), SUN(0);

        public final int dayValue;

        private Weekdays(int dayValue) {
            this.dayValue = dayValue;
        }
    }
    
    // 默认情况下，对枚举常量调用toString()会返回和name()一样的字符串。但是，toString()可以被覆写，而name()则不行。
    // 我们可以给Weekday添加toString()方法：
    enum Weekdayszh {
        MON(1, "星期一"), TUE(2, "星期二"), WED(3, "星期三"), THU(4, "星期四"), FRI(5, "星期五"), SAT(6, "星期六"), SUN(0, "星期日");

        public final int dayValue;
        private final String chinese;

        private Weekdayszh(int dayValue, String chinese) {
            this.dayValue = dayValue;
            this.chinese = chinese;
        }

        @Override
        public String toString() {
            return this.chinese;
        }
    }
    
    public enum Color {
        RED, GREEN, BLUE;
    }
}
